package utils

import (
	"crypto/md5"
	"crypto/rand"
	"encoding/hex"
	"io"
	"lingc/config"
	"lingc/models"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
	"golang.org/x/net/html"
	"gorm.io/gorm"
)

const ErrorTokenMsg = "token错误"

// Claims JWT 声明结构体
type Claims struct {
	ID       uint   `json:"id"`
	Username string `json:"username"`
	Avatar   string `json:"avatar"`
	Nickame  string `json:"nick_name"`
	// member 成员, admin 管理员
	Type string `json:"type"`
	jwt.StandardClaims
}

// OutData 输出数据结构体
type OutData struct {
	Msg  string      `json:"msg"`
	Code int         `json:"code"`
	Data interface{} `json:"data"`
}

// RedisClient Redis 客户端
var RedisClient *redis.Client

var MysqlClient *gorm.DB

// GenerateMD5 生成 MD5 值
func GenerateMD5(input string) string {
	hasher := md5.New()
	hasher.Write([]byte(input))
	return hex.EncodeToString(hasher.Sum(nil))
}

// GenerateToken 生成一个新的token
func GenerateToken(user Claims, TokenTime int64) (string, error) {
	// 创建一个我们自己的声明
	expirationTime := time.Now().Add(time.Duration(TokenTime) * time.Minute)
	claims := &Claims{
		ID:       user.ID,
		Username: user.Username,
		Type:     user.Type,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expirationTime.Unix(),
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	// 使用密钥签名并获得完整的编码后的字符串token
	return token.SignedString([]byte(config.JwtKey))
}

// ValidateToken 检查token是否有效
func ValidateToken(tokenString string) *Claims {
	// 解析token
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		// Don't forget to validate the alg is what you expect:
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, nil
		}
		return []byte(config.JwtKey), nil
	})

	if err != nil {
		return nil
	}

	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		return claims
	}

	return nil
}

// GetMenusUserRoute 根据用户权限获取路由
func GetMenusUserRoute(ruleID []uint, UserMenus []models.AuthRuleData) []string {
	var filteredMenus []string
	for _, v := range UserMenus {
		for _, id := range ruleID {
			if v.ID == id {
				filteredMenus = append(filteredMenus, v.Name) // Assuming there is a Name field in AuthRule
				break
			}
		}

	}
	return filteredMenus
}

// GetMenusUser 根据用户权限获取路由
func GetMenusUser(ruleID []uint, UserMenus []models.AuthRuleData) []*models.AuthRuleMenus {

	var filteredMenus = []models.AuthRuleMenus{}
	for _, v := range UserMenus {
		for _, id := range ruleID {
			if v.ID == id && (v.Type == 0 || v.Type == 1) {
				component := "Layout"
				if v.ParentID != 0 && v.URL != "" {
					component = v.URL
				}
				path := v.URL
				if path == "" {
					path = "/" + v.Name
				}
				filteredMenus = append(filteredMenus, models.AuthRuleMenus{
					ID:       v.ID,
					ParentID: v.ParentID,
					Name:     v.Name,
					Meta: models.AuthRuleMeta{
						Title:      v.Title,
						Icon:       v.Icon,
						Hidden:     false,
						AlwaysShow: false,
						Params:     v.URLParam,
						KeepAlive:  true,
					},
					Component: component,
					Path:      path,
					Rank:      v.Rank,
					Children:  []*models.AuthRuleMenus{}, // 初始化 Children 字段
				})
			}
		}
	}
	return ArrayToTree(filteredMenus)
}

// ArrayToTree 将数组转换为树状结构
func ArrayToTree(menuItems []models.AuthRuleMenus) []*models.AuthRuleMenus {
	// 创建一个map用于快速查找节点
	lookup := make(map[int]*models.AuthRuleMenus)
	var rootItems []*models.AuthRuleMenus

	for i := range menuItems {
		item := &menuItems[i]
		lookup[int(item.ID)] = item

		if item.ParentID == 0 {
			// 如果ParentID是0，则认为它是根节点
			rootItems = append(rootItems, item)
		} else {
			// 查找父节点并添加当前节点为其子节点
			if parent, found := lookup[int(item.ParentID)]; found {
				parent.Children = append(parent.Children, item)
			}
		}
	}

	return rootItems
}

// ArrayToTree 将数组转换为树状结构
func ArrayToTreeOptions(menuItems []*models.AuthRuleOptions) []*models.AuthRuleOptions {
	// 创建一个map用于快速查找节点
	lookup := make(map[int]*models.AuthRuleOptions)
	var rootItems []*models.AuthRuleOptions

	for i := range menuItems {
		item := menuItems[i]
		lookup[int(item.Value)] = item

		if item.ParentID == 0 {
			// 如果ParentID是0，则认为它是根节点
			rootItems = append(rootItems, item)
		} else {
			// 查找父节点并添加当前节点为其子节点
			if parent, found := lookup[int(item.ParentID)]; found {
				parent.Children = append(parent.Children, item)
			}
		}
	}

	return rootItems
}

// ArrayToTree 将数组转换为树状结构
func ArrayToTreeList(menuItems []*models.AuthRuleList) []*models.AuthRuleList {
	// 创建一个map用于快速查找节点
	lookup := make(map[int]*models.AuthRuleList)
	var rootItems []*models.AuthRuleList

	for i := range menuItems {
		item := menuItems[i]
		lookup[int(item.ID)] = item

		if item.ParentID == 0 {
			// 如果ParentID是0，则认为它是根节点
			rootItems = append(rootItems, item)
		} else {
			// 查找父节点并添加当前节点为其子节点
			if parent, found := lookup[int(item.ParentID)]; found {
				parent.Children = append(parent.Children, item)
			}
		}
	}

	return rootItems
}

// ArrayToTreeChildrenId
func ArrayToTreeChildrenId(menuItems []*models.AuthRuleOptions) []uint {
	// 创建一个map用于快速查找节点
	rule_ids := []uint{}
	if len(menuItems) == 0 {
		return rule_ids
	}
	lookup := make(map[int]interface{})
	lookuppid := make(map[int]interface{})
	for i := range menuItems {
		item := menuItems[i]
		lookup[int(item.Value)] = 1
		lookuppid[int(item.ParentID)] = 1
	}
	for key := range lookup {
		if lookuppid[key] == nil {
			rule_ids = append(rule_ids, uint(key))
		}
	}
	return rule_ids
}

// AddMenuNode 添加一级菜单
func AddMenuNode(title, name, icon string, rank uint) (uint, error) {
	mapData := map[string]interface{}{
		"name": name,
	}
	var temp models.AuthRule
	result := MysqlClient.Where(mapData).First(&temp)
	if result.Error == nil {
		return uint(temp.ID), nil
	}

	indexData := models.AuthRule{
		Name:      name,
		Title:     title,
		URL:       "",
		Type:      0,
		Icon:      icon,
		APIMethod: 0,
		Rank:      rank,
		ParentID:  0,
	}
	result = MysqlClient.Create(&indexData)
	if result.Error != nil {
		return 0, result.Error
	}
	return uint(indexData.ID), nil
}

// AddChildNode 添加子级菜单
func AddChildNode(title, name string, pid uint, rank uint) error {
	mapData := map[string]interface{}{
		"name": name + "Index",
	}
	var temp models.AuthRule
	result := MysqlClient.Where(mapData).First(&temp)
	var pidIndex uint
	if result.Error == nil {
		pidIndex = uint(temp.ID)
	} else {
		indexData := models.AuthRule{
			Name:      name + "Index",
			Title:     title,
			URL:       "/" + name + "/index",
			Type:      1,
			Icon:      "",
			APIMethod: 0,
			Rank:      rank,
			ParentID:  pid,
		}
		result = MysqlClient.Create(&indexData)
		if result.Error != nil {
			return result.Error
		}
		pidIndex = uint(indexData.ID)

		indexEdit := models.AuthRule{
			Name:      name + "Edit",
			Title:     "编辑",
			URL:       "/" + name + "/edit",
			URLParam:  "/:id?",
			Type:      2,
			Icon:      "",
			APIMethod: 0,
			Rank:      rank + 1,
			ParentID:  uint(pidIndex),
		}
		result = MysqlClient.Create(&indexEdit)
		if result.Error != nil {
			return result.Error
		}
	}

	mapData = map[string]interface{}{
		"name": name + "/page",
	}
	result = MysqlClient.Where(mapData).First(&temp)
	if result.Error == nil {
		return nil
	}

	indexChild := []models.AuthRule{
		{
			Name:      name + "/page",
			Title:     "获取列表",
			URL:       name + "/page",
			Type:      4,
			Icon:      "",
			APIMethod: 1,
			Rank:      2,
			ParentID:  pidIndex,
		},
		{
			Name:      name + "/info",
			Title:     "获取详情",
			URL:       name + "/info",
			Type:      4,
			Icon:      "",
			APIMethod: 1,
			Rank:      3,
			ParentID:  pidIndex,
		},
		{
			Name:      name + "/create",
			Title:     "新增数据",
			URL:       name + "/create",
			Type:      4,
			Icon:      "",
			APIMethod: 2,
			Rank:      4,
			ParentID:  pidIndex,
		},
		{
			Name:      name + "/update",
			Title:     "更新数据",
			URL:       name + "/update",
			Type:      4,
			Icon:      "",
			APIMethod: 2,
			Rank:      4,
			ParentID:  pidIndex,
		},
		{
			Name:      name + "/delete",
			Title:     "删除数据",
			URL:       name + "/delete",
			Type:      4,
			Icon:      "",
			APIMethod: 2,
			Rank:      6,
			ParentID:  pidIndex,
		},
		{
			Name:      name + "Status",
			Title:     "状态按钮",
			URL:       "",
			Type:      3,
			Icon:      "",
			APIMethod: 0,
			Rank:      7,
			ParentID:  pidIndex,
		},
		{
			Name:      name + "DelBtn",
			Title:     "删除按钮",
			URL:       "",
			Type:      3,
			Icon:      "",
			APIMethod: 0,
			Rank:      8,
			ParentID:  pidIndex,
		},
	}
	result = MysqlClient.Create(&indexChild)
	if result.Error != nil {
		return result.Error
	}
	return nil
}

// Contains 检查slice中是否包含item
func Contains(slice []string, item string) bool {
	for _, s := range slice {
		if s == item {
			return true
		}
	}
	return false
}

// GetClientIP 获取客户端IP
func GetClientIP(c *gin.Context) string {
	ip := c.ClientIP()
	if ip == "::1" {
		ip = "127.0.0.1"
	}
	return ip
}

// StrToInt64 将字符串转换为int64
func StrToInt64(str string) int64 {
	result, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		return 0
	}
	return result
}

// UintSliceToString 将 []uint 转换为逗号分隔的字符串
func UintSliceToString(slice []uint, separator string) string {
	if len(slice) == 0 {
		return ""
	}
	var result []string
	for _, num := range slice {
		result = append(result, strconv.FormatUint(uint64(num), 10))
	}
	return strings.Join(result, separator)
}

// StringToUintSlice 将逗号分隔的字符串转换为 []uint
func StringToUintSlice(str string) []uint {
	if str == "" {
		return []uint{}
	}
	var result []uint
	for _, numStr := range strings.Split(str, ",") {
		num, err := strconv.ParseUint(numStr, 10, 64)
		if err != nil {
			continue
		}
		result = append(result, uint(num))
	}
	return result
}

// InArray 检查一个值是否存在于 []uint 中
func InArray(arr []uint, val uint) bool {
	for _, v := range arr {
		if v == val {
			return true
		}
	}
	return false
}

// MyhasString 检查一个值是否存在于 []string 中
func MyhasString(str string, val []string) bool {
	for _, v := range val {
		if strings.Contains(str, v) {
			return true
		}
	}
	return false
}

// ParseFloat 将字符串转换为浮点数
func ParseFloat(str string) float64 {
	if str == "" {
		return 0
	}
	num, err := strconv.Atoi(str)
	if err != nil {
		return 0
	}
	return float64(num)
}

// GetRandomString 生成随机字符串
func GetRandomString(length int) string {
	const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
	charsetBytes := []byte(charset)
	b := make([]byte, length)
	n, err := io.ReadAtLeast(rand.Reader, b, length)
	if n != length || err != nil {
		return ""
	}
	for i := 0; i < length; i++ {
		b[i] = charsetBytes[int(b[i])%len(charsetBytes)] // 映射到charset中的字符
	}
	return string(b)
}

// StrToTime 时间字符串转时间戳
func StrToTime(str string) int64 {
	//把时间字符串转成时间戳 秒
	time_temp, err := time.ParseInLocation("2006-01-02 15:04:05", str, time.Local)
	// log.Printf("time_temp:%v,str:%v", time_temp, str)
	if err != nil {
		// log.Printf("time_temp:%v", time.Now().Unix())
		return time.Now().Unix()
	}
	// log.Printf("time_temp:%v", time_temp.Unix())
	return time_temp.Unix()
}

// RemoveStringElement 从切片中移除指定的元素
func RemoveStringElement(slice []string, value string) []string {
	var result []string
	for _, item := range slice {
		if item != value {
			result = append(result, item)
		}
	}
	return result
}

// ArraySortByField 根据字段排序
func ArraySortByField(list []*models.ChatGroupList, field string, orderby string) []*models.ChatGroupList {
	sort.Slice(list, func(i, j int) bool {
		iValue := list[i].UpdatedAt
		jValue := list[j].UpdatedAt
		if orderby == "desc" {
			return iValue > jValue
		}
		return iValue < jValue
	})
	return list
}

// StripTags 去除HTML标签
func StripTags(s string) string {
	var buf strings.Builder
	z := html.NewTokenizer(strings.NewReader(s))
	for {
		tt := z.Next()
		switch tt {
		case html.ErrorToken:
			return buf.String()
		case html.TextToken:
			buf.Write(z.Text())
		}
	}
}

// StrSubLength 截取字符串长度
func StrSubLength(str string, length int) string {
	return string([]rune(str)[:length])
}
